TITLE 09/09/83 PRINT BIOS
.XLIST
INCLUDE DSEG.SRC
INCLUDE POSTEQU.SRC
.LIST
INCLUDE SEGMENT.SRC

EXTRN	DDS:NEAR
PUBLIC	PRINTER_IO_1

;--- INT 17 -----------------------------------------------------
; PRINTER_IO
;	THIS ROUTINE PROVIDES COMMUNICATION WITH THE PRINTER
; INPUT
;	(AH)=0	PRINT THE CHARACTER IN (AL)
;		ON RETURN, AH=1 IF CHARACTER COULD NOT BE PRINTED (TIME OUT)
;		OTHER BITS SET AS ON NORMAL STATUS CALL
;	(AH)=1	INITIALIZE THE PRINTER PORT
;		RETURNS WITH (AH) SET WITH PRINTER STATUS
;	(AH)=2	READ THE PRINTER STATUS INTO (AH)
;		7	6	5	4	3	2-1	0
;		|	|	|	|	|	|	|_TIME OUT
;		|	|	|	|	|	|_ UNUSED
;		|	|	|	|	|_ 1 = I/O ERROR
;		|	|	|	|_ 1 = SELECTED
;		|	|	|_ 1 = OUT OF PAPER
;		|	|_ 1 = ACKNOWLEDGE
;		|_ 1 = NOT BUSY
;
;	(DX) = PRINTER TO BE USED (0,1,2) CORRESPONDING TO ACTUAL VALUES
;		IN PRINTER_BASE AREA
; DATA AREA PRINTER_BASE CONTAINS THE BASE ADDRESS OF THE PRINTER CARD(S)
; AVAILABLE (LOCATED AT BEGINNING OF DATA SEGMENT, 408H ABSOLUTE, 3 WORDS)
;
; DATA AREA PRINT_TIM_OUT (BYTE) MAY BE CHANGE TO CAUSE DIFFERENT
; TIME OUT WAITS. DEFAULT=20 * 4
;
; REGISTERS	AH IS MODIFIED WITH STATUS INFORMATION
;		ALL OTHERS UNCHANGED
;----------------------------------------------------------------
	ASSUME	CS:CODE,DS:DATA

PRINTER_IO_1	PROC	FAR		; ENTRY POINT FOR ORG 0EFD2H
	STI				; INTERRUPTS BACK ON
	PUSH	DS			; SAVE SEGMENT
	PUSH	DX
	PUSH	SI
	PUSH	CX
	PUSH	BX
	CALL	DDS
	MOV	SI,DX			; GET PRINTER PARM
	MOV	BL,PRINT_TIM_OUT[SI]	; LOAD TIMEOUT VALUE
	SHL	SI,1			; WORD OFFSET INTO TABLE
	MOV	DX,PRINTER_BASE[SI]	; GET BASE ADDRESS FOR PRINTER CARD
	OR	DX,DX			; TEST DX FOR ZERO, INDICATING NO PRINTER
	JZ	B1			; EXIT, NO PRINTER ADAPTER AT OFFSET
	OR	AH,AH			; TEST FOR (AH)=0
	JZ	B2			; PRINT_AL
	DEC	AH			; TEST FOR (AH)=1
	JZ	B8			; INIT_PRT
	DEC	AH			; TEST FOR (AH)=2
	JZ	B5			; PRINTER STATUS
B1:					; RETURN
	POP	BX
	POP	CX
	POP	SI			; RECOVER REGISTERS
	POP	DX			; RECOVER REGISTERS
	POP	DS
	IRET

;------ PRINT THE CHARACTER IN (AL)

B2:
	PUSH	AX		; SAVE VALUE TO PRINT
	OUT	DX,AL		; OUTPUT CHAR TO PORT
	INC	DX		; POINT TO STATUS PORT

;------- CHECK FOR PRINTER BUSY

	PUSH	BX		;
	IN	AL,DX		; GET STATUS
	TEST	AL,80H		; IS THE PRINTER CURRENTLY BUSY
	JNZ	B2_A		; OUT_STROBE

;-------- INT 15 DEVICE BUSY

	MOV	AX,90FEH	; FUNCTION 90 PRINTER ID
	INT	15H		;

;------ADJUST OUTER LOOP

B2_A:
	SUB	BH,BH		; CLEAR BH
	RCL	BX,1		; MULT BY 4
	RCL	BX,1
;
;------WAIT BUSY
;

B3:	SUB	CX,CX		; INNER LOOP (64K)
B3_1:	IN	AL,DX		; GET STATUS
	MOV	AH,AL		; STATUS TO AH ALSO
	TEST	AL,80H		; IS THE PRINTER CURRENTLY BUSY
	JNZ	B4		; OUT_STROBE
	LOOP	B3_1		; LOOP IF NOT
	DEC	BX		; DROP OUTER LOOP COUNT ------
	JNZ	B3		; MAKE ANOTHER PASS IF NOT ZERO

	POP	BX		; RESTORE BX -------
	OR	AH,1		; SET ERROR FLAG
	AND	AH,0F9H 	; TURN OFF THE UNUSED BITS
	JMP	SHORT B7	; RETURN WITH ERROR FLAG SET
B4:	POP	BX		; RESTORE BX -------
				; OUT_STROBE
	MOV	AL,0DH		; SET THE STROBE HIGH
	INC	DX
	OUT	DX,AL
	MOV	AL,0CH		; SET THE STROBE LOW
	JMP	SHORT $+2	; IO DELAY
	OUT	DX,AL
	POP	AX		; RECOVER THE OUTPUT CHAR

;------ PRINTER STATUS

B5:
	PUSH	AX		; SAVE AL REG
B6:
	MOV	DX,PRINTER_BASE[SI]
	INC	DX
	IN	AL,DX		; GET PRINTER STATUS
	MOV	AH,AL
	AND	AH,0F8H 	; TURN OFF UNUSED BITS
B7:
	POP	DX		; RECOVER AL REG
	MOV	AL,DL		; GET CHARACTER INTO AL
	XOR	AH,48H		; FLIP A COUPLE OF BITS
	JMP	B1		; RETURN FROM ROUTINE

;------ INITIALIZE THE PRINTER PORT

B8:
	PUSH	AX		; SAVE AL
	INC	DX		; POINT TO OUTPUT PORT
	INC	DX
	MOV	AL,8		; SET INIT LINE LOW
	OUT	DX,AL
	MOV	AX,1000*4	; -------
B9:				; INIT_LOOP
	DEC	AX		; LOOP FOR RESET TO TAKE
	JNZ	B9		; INIT_LOOP
	MOV	AL,0CH		; NO INTERRUPTS, NON AUTO LF, INIT HIGH
	OUT	DX,AL
	JMP	B6		; PRT_STATUS_1
PRINTER_IO_1	ENDP
	CODE	ENDS
		END
